using System;
using System.Diagnostics;
using OpenTK;
using BepuUtilities;
using OpenTK.Graphics;
using System.Threading;
#if MYCODE
using BepuUtilities.Vectors;
#else
using Vector2 = System.Numerics.Vector2;
#endif
namespace DemoUtilities
{
    public enum WindowMode
    {
        FullScreen,
        Windowed
    }

    /// <summary>
    /// 简单且不是非常通用的窗口管理。
    /// </summary>
    public class Window : IDisposable
    {
        internal NativeWindow window;

        private bool resized;

        private WindowMode windowMode;
        WindowMode WindowMode
        {
            get
            {
                return windowMode;
            }
            set
            {
                switch (value)
                {
                    case WindowMode.FullScreen:
                        if (windowMode != WindowMode.FullScreen)
                        {
                            windowMode = value;
                            window.WindowState = WindowState.Fullscreen;
                            window.WindowBorder = WindowBorder.Hidden;
                            window.Location = new Point(0, 0);
                            var primaryBounds = DisplayDevice.Default.Bounds;
                            window.Size = new Size(primaryBounds.Width, primaryBounds.Height);
                            resized = true;
                        }
                        break;
                    case WindowMode.Windowed:
                        if (windowMode != WindowMode.Windowed)
                        {
                            windowMode = value;
                            window.WindowState = WindowState.Normal;
                            window.WindowBorder = WindowBorder.Resizable;
                            resized = true;
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// 获取或设置窗口正文的分辨率。
        /// </summary>
        public Int2 Resolution
        {
            get
            {
                return new Int2(window.ClientSize.Width, window.ClientSize.Height);
            }
            set
            {
                window.ClientSize = new Size(value.X, value.Y);
                resized = true;
            }
        }

        public IntPtr Handle { get { return window.WindowInfo.Handle; } }

        /// <summary>
        /// 获取窗口当前是否处于焦点状态。
        /// </summary>
        public bool Focused { get { return window.Focused; } }


        /// <summary>
        /// 构造一个新的支持呈现的窗口。
        /// </summary>
        /// <param name="title">窗口的标题。</param>
        /// <param name="Resolution">窗口可绘制表面的初始大小(像素)。</param>
        /// <param name="location">窗口可绘制表面的初始位置。</param>
        /// <param name="windowMode">初始窗口模式。</param>
        public Window(string title, Int2 resolution, Int2 location, WindowMode windowMode)
        {
            window = new NativeWindow(location.X, location.Y, resolution.X, resolution.Y, title, GameWindowFlags.FixedWindow, GraphicsMode.Default, DisplayDevice.Default);
            Debug.Assert(window.ClientSize.Width == resolution.X);
            Debug.Assert(window.ClientSize.Height == resolution.Y);
            window.Visible = true;
            Resolution = resolution;
            window.Resize += (form, args) => resized = true;
            window.Closing += OnClosing;

            window.WindowBorder = WindowBorder.Resizable;

            WindowMode = windowMode;

        }
        /// <summary>
        /// 构造一个新的支持呈现的窗口。
        /// </summary>
        /// <param name="title">窗口的标题。</param>
        /// <param name="Resolution">窗口可绘制表面的初始大小(像素)。</param>
        /// <param name="windowMode">初始窗口模式。</param>
        public Window(string title, Int2 resolution, WindowMode windowMode)
            : this(title, resolution, new Int2((DisplayDevice.Default.Width - resolution.X) / 2, (DisplayDevice.Default.Height - resolution.Y) / 2), windowMode)
        {
        }

        public Vector2 GetNormalizedMousePosition(Int2 mousePosition)
        {
            return new Vector2((float)mousePosition.X / Resolution.X, (float)mousePosition.Y / Resolution.Y);
        }

        private void OnClosing(object sender, EventArgs e)
        {
            // 这将冗余地调用Windows.Close,但这没有问题。
            tryToClose = true;
        }

        private bool windowUpdateLoopRunning;
        private bool tryToClose;
        /// <summary>
        /// 在下一个可用商机时关闭窗口。
        /// </summary>
        public void Close()
        {
            if (windowUpdateLoopRunning)
                tryToClose = true;
            else
                window.Close();
        }


        /// <summary>
        /// 启动窗口的更新循环。在每次调用更新处理程序之前处理事件。
        /// </summary>
        /// <param name="updateHandler">要在循环内重复调用的委托。</param>
        public void Run(Action<float> updateHandler, Action<Int2> onResize)
        {
            long previousTime = Stopwatch.GetTimestamp();
            windowUpdateLoopRunning = true;
            while (true)
            {
                if (disposed)
                    break;
                if (resized)
                {
                    // 请注意,将窗口最小化或调整为无效大小并不会导致实际的调整大小尝试。不允许零宽度呈现表面。
                    if (window.Width > 0 && window.Height > 0)
                    {
                        onResize(new Int2(window.Width, window.Height));
                    }
                    resized = false;
                }
                window.ProcessEvents();
                if (tryToClose)
                {
                    window.Close();
                    break;
                }
                long time = Stopwatch.GetTimestamp();
                var dt = (float)((time - previousTime) / (double)Stopwatch.Frequency);
                previousTime = time;

                if (window.WindowState != WindowState.Minimized)
                {
                    updateHandler(dt);
                }
                else
                {
                    // 如果窗口被最小化,请稍作休息。
                    Thread.Sleep(1);
                }
            }
            windowUpdateLoopRunning = false;
        }

        private bool disposed;
        public void Dispose()
        {
            if (!disposed)
            {
                window.Dispose();
                disposed = true;
            }
        }

    }
}
